package com.lyn.solitude.pluginhost.uitls

import android.text.TextUtils
import android.util.Log
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.Objects
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
import kotlin.math.min

/**
 * 外网监听工具类
 *
 * @author longyn 2023/4/27
 * @version 1.0.0
 */
@OptIn(DelicateCoroutinesApi::class)
object NetworkUtil {
    private const val TAG = "NetworkUtil"

    private var isExtranet = true
    private var interval: Long = 5000
    private var position = 0

    private val hosts = arrayOf(
        "a1.tuyacn.com",
        "www.baidu.com",
        "www.taobao.com",
        "www.aliyun.com",
        "www.google.com"
    )


    class PingData(var success: Boolean, var ms: Long)

    private var listener: NetworkListener? = null

    init {
        GlobalScope.launch(Dispatchers.IO) {
            while (true) {
                delay(interval)
                var existNetwork = false
                val pingData = ping(hosts[position])
                if (pingData != null && pingData.success) {
                    withContext(Dispatchers.Main) {
                        listener?.onMs(pingData.ms)
                    }
                    existNetwork = true
                } else {
                    for (host in hosts) {
                        val fpingData = ping(host)
                        if (fpingData != null && fpingData.success) {
                            withContext(Dispatchers.Main) {
                                listener?.onMs(fpingData.ms)

                            }
                            existNetwork = true
                            break
                        }
                        withContext(Dispatchers.Main) {
                            listener?.onMs(-1L)
                        }
                    }
                }
                if (isExtranet != existNetwork) {
                    val finalExistNetwork = existNetwork
                    withContext(Dispatchers.Main) {
                        listener?.onChange(finalExistNetwork)
                    }
                }
                isExtranet = existNetwork
            }
        }
    }

    /**
     * 设置监听器
     */
    fun setNetworkListener(listener: NetworkListener?) {
        this.listener = listener
    }

    /**
     * 设置ping 间隔时间
     * @param interval 间隔时间 ms
     */
    fun setInterval(interval: Long) {
        this.interval = interval
    }

    /**
     * 获取ping地址列表
     */
    fun getPingAddressArray(): Array<String> {
        return this.hosts
    }

    /**
     * 设置ping 地址索引
     */
    fun setPingAddressPosition(position: Int) {
        this.position = position
    }

    /**
     * 获取ping 地址索引
     */
    fun getPingAddressPosition(): Int {
        return this.position
    }


    private fun parserMS(input: String): Long {
        try {
            val pattern = Pattern.compile("time=(\\d+)")
            val matcher = pattern.matcher(input)
            if (matcher.find()) {
                return Objects.requireNonNull(matcher.group(1)).toLong()
            }
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return 0L
    }

    /**
     * ping 网络
     */
    private fun ping(host: String): PingData? {
        var process: Process? = null
        var reader: BufferedReader? = null
        try {
            process = Runtime.getRuntime().exec("ping -c 1 $host")
            val timeout: Long = 1000
            val startTime = System.nanoTime()
            var rem = TimeUnit.MILLISECONDS.toNanos(timeout)
            do {
                try {
                    process.exitValue()
                    break
                } catch (ex: IllegalThreadStateException) {
                    if (rem > 0) Thread.sleep(
                        min((TimeUnit.NANOSECONDS.toMillis(rem) + 1).toDouble(), 100.0)
                            .toLong()
                    )
                }
                rem = TimeUnit.MILLISECONDS.toNanos(timeout) - (System.nanoTime() - startTime)
            } while (rem > 0)
            reader = BufferedReader(InputStreamReader(process.inputStream))
            if (!reader.ready()) {
                return PingData(false, -1)
            }
            val sb = StringBuilder()
            var readLine: String?
            while (reader.readLine().also { readLine = it } != null) {
                sb.append(readLine).append("\n")
            }
            val value = sb.toString()
            var success = false
            if (!TextUtils.isEmpty(value)) {
                if (value.contains("ttl")) {
                    success = true
                } else {
                    Log.d(TAG, value)
                }
            }
            val ms = parserMS(value)
            return PingData(success, ms)
        } catch (e: Throwable) {
            e.printStackTrace()
        } finally {
            try {
                reader?.close()
            } catch (e: Throwable) {
                e.printStackTrace()
            }
            try {
                process?.destroy()
            } catch (e: Throwable) {
                e.printStackTrace()
            }
        }
        return null
    }


    interface NetworkListener {
        fun onChange(enabled: Boolean)
        fun onMs(ms: Long)
    }


}